home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C ++ / Frameworks / MacZoop 1.6.5 / Basic Classes / Z Sources / ZWindow.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1997-07-21  |  35.4 KB  |  1,383 lines  |  [TEXT/CWIE]

  1. /*************************************************************************************************
  2. *
  3. *
  4. *            ObjectMacZapp        -- a standard Mac OOP application template
  5. *
  6. *
  7. *
  8. *            ZWindow.cpp            -- the window object
  9. *
  10. *
  11. *
  12. *
  13. *
  14. *            © 1996, Graham Cox
  15. *
  16. *            14/11/96- modified to support undo and printing.
  17. *
  18. *
  19. *************************************************************************************************/
  20.  
  21.  
  22. #include    "ZWindow.h"
  23. #include    "MacZoop.h"
  24. #include    "ZEventHandler.h"
  25. #include    "ZUndoTask.h"
  26.  
  27.  
  28. #ifdef APPEARANCE_MGR_AWARE
  29.     #include    "Appearance.h"
  30. #endif
  31.  
  32. static short CalculateOffsetAmount(    short idealStartPoint,
  33.                                     short idealEndPoint,
  34.                                     short idealOnScreenStartPoint,
  35.                                     short idealOnScreenEndPoint,
  36.                                     short screenEdge1,
  37.                                     short screenEdge2 );
  38.  
  39.  
  40. /*------------------------------***  CONSTRUCTOR  ***---------------------------------*/
  41.  
  42. ZWindow::ZWindow(ZCommander* aBoss, const short windowID)
  43.     : ZCommander(aBoss)
  44. {
  45.     windID = windowID;
  46.     macWindow = NULL;
  47.     dirty = FALSE;
  48.     isNamed = FALSE;
  49.     macFile.vRefNum = kNoFile;
  50.     macFType = 0;
  51.     printable = FALSE;
  52.     isPrinting = FALSE;
  53.     floating = FALSE;
  54.     disableAutoClose = FALSE;
  55.     
  56.     // initial sizeRect is set to an arbitrary size
  57.     
  58.     SetRect(&sizeRect,120,90,2000,2000);
  59. }
  60.  
  61. /*------------------------------***  DESTRUCTOR  ***---------------------------------*/
  62.  
  63. ZWindow::~ZWindow()
  64. {
  65.     // if the application has an undo task pertaining to this window, delete it.
  66.     
  67.     ZUndoTask*    curTask = gApplication->GetUndoTask();
  68.     
  69.     if (curTask && (curTask->GetUndoTarget() == this))
  70.         gApplication->SetTask( NULL );
  71.     
  72.     // wMgr no longer needs us
  73.         
  74.     gWindowManager->RemoveWindow( this );
  75.     
  76.     if ( macWindow )
  77.         DisposeWindow( macWindow );
  78. }
  79.  
  80.  
  81. /*--------------------------------***  INITZWINDOW  ***---------------------------------*/
  82. /*    
  83.  
  84. initialise this object. By default, this just makes the window
  85. ----------------------------------------------------------------------------------------*/
  86.  
  87. void    ZWindow::InitZWindow()
  88. {
  89.     MakeMacWindow( windID );
  90.     
  91.     // tell the window manager of our existence. This must be done after the
  92.     // full build of the mac window since the window manager needs to get
  93.     // information from it. Thus if you override this method, make sure you
  94.     // make the same call.
  95.     
  96.     gWindowManager->AddWindow( this );
  97. }
  98.  
  99.  
  100. /*------------------------------***  MAKEMACWINDOW  ***---------------------------------*/
  101. /*    
  102.  
  103. create the macintosh window that this object looks after
  104. ----------------------------------------------------------------------------------------*/
  105.  
  106. void    ZWindow::MakeMacWindow( const short windID )
  107. {
  108.     if ( gMacInfo.supportsColour )
  109.         FailNIL( macWindow = GetNewCWindow( windID, NULL, NULL ));
  110.     else
  111.         FailNIL( macWindow = GetNewWindow( windID, NULL, NULL ));
  112.         
  113.     // so we can identify the window, we set the windowKind to a special value. The refCon
  114.     // contains the object reference so we can freely locate the object from the window and
  115.     // vice versa. Your application must not touch the refCon- add members to your window
  116.     // objects instead.
  117.     
  118.     ((WindowPeek) macWindow)->windowKind = IS_ZWINDOW_KIND;
  119.     SetWRefCon( macWindow, (long) this );
  120.     
  121.     // what WDEF are we using for this window? If it's one of the known "floater" types,
  122.     // then we should set the flaoting flag automatically- one less thing the programmer
  123.     // needs to worry about, and will work for the common cases.
  124.     
  125.     WindTemplateHdl        wTH = (WindTemplateHdl) GetResource( 'WIND', windID );
  126.     
  127.     if ( wTH )
  128.     {
  129.         // the system floater has a proc of 124. The commonly used "Infinity" windoid
  130.         // has a proc of 128.
  131.         
  132.         short    pID = (*wTH)->procID / 16;
  133.         
  134.         // with appearance manager, the WDEF IDs for floating windows are 66 & 67
  135.         
  136.         #ifdef APPEARANCE_MGR_AWARE
  137.         
  138.         if ( gMacInfo.hasAppearanceMgr )
  139.             floating |= (     pID == kStdUtilityDefProcResID ||
  140.                             pID == kStdUtilitySideTitleDefProcResID );
  141.         
  142.         #endif
  143.         
  144.         floating |= (    pID == kFloatingWindowDefinition ||
  145.                         pID == kInfinityWindoidDefinition );
  146.  
  147.         ReleaseResource((Handle) wTH );
  148.     }
  149.     
  150.     // allocate a unique title. This we'll base on the current title
  151.     // (which should be "untitled"), with an appended digit to ensure uniqueness
  152.     
  153.     Str255    wTitle;
  154.     
  155.     GetWTitle( macWindow, wTitle );
  156.     if ( gWindowManager->GetUniqueUntitledName( wTitle ))
  157.         SetWTitle( macWindow, wTitle );
  158.         
  159.     CopyPString( wTitle, macFile.name );
  160.         
  161.     // if appearance savvy, make a root control for the window so stuff can be
  162.     // embedded into it easily.
  163.     
  164.     #ifdef APPEARANCE_MGR_AWARE
  165.     
  166.     if ( gMacInfo.hasAppearanceMgr )
  167.     {
  168.         ControlHandle    rc;
  169.         
  170.         FailOSErr( CreateRootControl( macWindow, &rc ));
  171.     }
  172.     
  173.     #endif
  174. }
  175.  
  176.  
  177. /*----------------------------------***  ACTIVATE  ***----------------------------------*/
  178. /*    
  179.  
  180. this window is becoming active
  181. ----------------------------------------------------------------------------------------*/
  182.  
  183. void    ZWindow::Activate()
  184. {
  185.     // the window is activated. If appearance mgr savvy, activate root control:
  186.     
  187.     #ifdef APPEARANCE_MGR_AWARE
  188.     
  189.     if ( gMacInfo.hasAppearanceMgr )
  190.     {
  191.         OSErr            theErr;
  192.         ControlHandle     rc;
  193.         
  194.         theErr = GetRootControl( macWindow, &rc );
  195.         
  196.         if ( theErr == noErr )
  197.             FailOSErr( ActivateControl( rc ));
  198.     }
  199.     else
  200.         DrawGrow();
  201.     
  202.     #else
  203.     
  204.     DrawGrow();
  205.     
  206.     #endif
  207. }
  208.  
  209.  
  210. /*---------------------------------***  DEACTIVATE  ***---------------------------------*/
  211. /*    
  212.  
  213. this window is becoming inactive
  214. ----------------------------------------------------------------------------------------*/
  215.  
  216. void    ZWindow::Deactivate()
  217. {
  218.     #ifdef APPEARANCE_MGR_AWARE
  219.     
  220.     if ( gMacInfo.hasAppearanceMgr )
  221.     {
  222.         OSErr            theErr;
  223.         ControlHandle     rc;
  224.         
  225.         theErr = GetRootControl( macWindow, &rc );
  226.         
  227.         if ( theErr == noErr )
  228.             FailOSErr( DeactivateControl( rc ));
  229.     }
  230.     else
  231.         DrawGrow();
  232.     
  233.     #else
  234.     
  235.     DrawGrow();
  236.     
  237.     #endif
  238. }
  239.  
  240.  
  241. /*------------------------------------***  FOCUS  ***-----------------------------------*/
  242. /*    
  243.  
  244. make this window the current port ready for drawing or clicking
  245. ----------------------------------------------------------------------------------------*/
  246.  
  247. void    ZWindow::Focus()
  248. {
  249.     SetPort( macWindow );
  250.     SetOrigin( 0, 0 );
  251.     ClipRect( &macWindow->portRect );
  252. }
  253.  
  254.  
  255. /*--------------------------------***  POSTREFRESH  ***---------------------------------*/
  256. /*    
  257.  
  258. invalidate the window contents so that it gets redrawn on the next update
  259. ----------------------------------------------------------------------------------------*/
  260.  
  261. void    ZWindow::PostRefresh()
  262. {
  263.     Focus();
  264.     InvalRect( &macWindow->portRect );
  265. }
  266.  
  267. /*------------------------------------***  DRAW  ***------------------------------------*/
  268. /*    
  269.  
  270. draw the contents of this window. This is the main draw dispatcher.
  271. ----------------------------------------------------------------------------------------*/
  272.  
  273. void    ZWindow::Draw()
  274. {
  275.     // if we are growable, we should clip out the scrollbar areas otherwise
  276.     // the DrawContent call may erase the growbox, etc
  277.     
  278.     short    v = GetWVariant(macWindow);
  279.     
  280.     if (v == documentProc || v == zoomDocProc)
  281.     {
  282.         Rect    r = macWindow->portRect;
  283.         
  284.         r.right -= kStdScrollbarWidth;
  285.         r.bottom -= kStdScrollbarWidth;
  286.         ClipRect( &r );
  287.     }
  288.     DrawContent();
  289.     
  290.     SetOrigin( 0, 0 );
  291.     ClipRect( &macWindow->portRect );        
  292.     DrawControls( macWindow );
  293.  
  294.     DrawGrow();
  295. }
  296.  
  297.  
  298. /*-------------------------------***  DRAWCONTENT  ***----------------------------------*/
  299. /*    
  300.  
  301. draw the content area of this window- this is what will draw the meaningful part
  302. ----------------------------------------------------------------------------------------*/
  303.  
  304. void    ZWindow::DrawContent()
  305. {
  306.     if (! isPrinting)
  307.         EraseRect( &macWindow->portRect );
  308. }
  309.  
  310.  
  311. /*---------------------------------***  CALCPAGES  ***----------------------------------*/
  312. /*    
  313.  
  314. compute the pagination for printing. By default this divides the contect rect up to be
  315. tiled across the paper rect, horizontal major order. Override for other methods
  316. ----------------------------------------------------------------------------------------*/
  317.  
  318. void    ZWindow::CalcPages( const Rect& paperRect, short* pagesH, short* pagesV )
  319. {
  320.     Rect    cr;
  321.     short    pWidth, pHeight, cWidth, cHeight;
  322.     
  323.     GetBounds( &cr );
  324.     
  325.     pWidth = paperRect.right - paperRect.left;
  326.     pHeight = paperRect.bottom - paperRect.top;
  327.     
  328.     cWidth = cr.right - cr.left;
  329.     cHeight = cr.bottom - cr.top;
  330.     
  331.     *pagesH = (cWidth / pWidth) + 1;
  332.     *pagesV = (cHeight / pHeight) + 1;
  333. }
  334.  
  335. /*-------------------------------***  PRINTONEPAGE  ***---------------------------------*/
  336. /*    
  337. draw the requested page (numbered according to the pagination you set up) to the current
  338. port, which will be a printing port when called. By default this manipulates the origin
  339. and draws the content, suitably clipped, to the port. Override for other behaviour.
  340. ----------------------------------------------------------------------------------------*/
  341.  
  342. void    ZWindow::PrintOnePage( const short pageNum, const Rect& paperRect )
  343. {
  344.     Rect    pr;
  345.     short    hp, vp, dH, dV;
  346.     
  347.     // calculate the printing area
  348.     
  349.     CalcPages( paperRect, &hp, &vp );
  350.     pr = paperRect;
  351.     
  352.     dH = paperRect.right  * ((pageNum - 1) % hp);
  353.     dV = paperRect.bottom * ((pageNum - 1) / hp);
  354.     
  355.     OffsetRect( &pr, dH, dV );
  356.     
  357.     // make sure that the text & pen attributes in the window and printing port match
  358.     // in case the DrawContent routine doesn't set them as it goes.
  359.     
  360.     TextFont( macWindow->txFont );
  361.     TextSize( macWindow->txSize );
  362.     TextFace( macWindow->txFace );
  363.     TextMode( srcOr );
  364.     PenSize( macWindow->pnSize.h, macWindow->pnSize.v );
  365.     PenPat( &macWindow->pnPat );
  366.     PenMode( macWindow->pnMode );
  367.     
  368.     // draw the contents.
  369.     
  370.     SetOrigin( pr.left, pr.top );
  371.     ClipRect( &pr );
  372.     
  373.     DrawContent();
  374.     SetOrigin( 0, 0 );
  375. }
  376.  
  377.  
  378. /*------------------------------***  GETCONTENTRECT  ***--------------------------------*/
  379. /*    
  380.  
  381. return the content area
  382. ----------------------------------------------------------------------------------------*/
  383.  
  384. void    ZWindow::GetContentRect( Rect* contents )
  385. {
  386.     *contents = macWindow->portRect;
  387. }
  388.  
  389.  
  390.  
  391. /*---------------------------------***  DRAWGROW  ***-----------------------------------*/
  392. /*    
  393.  
  394. draw the grow icon if the window type indicates this is appropriate
  395. ----------------------------------------------------------------------------------------*/
  396.  
  397. void    ZWindow::DrawGrow()
  398. {
  399.     short    v = GetWVariant(macWindow);
  400.     
  401.     if ( v == documentProc || v == zoomDocProc )
  402.     {
  403.         Rect    r = macWindow->portRect;
  404.         
  405.         r.left = r.right - kStdScrollbarWidth;
  406.         r.top = r.bottom - kStdScrollbarWidth;
  407.         
  408.         ClipRect( &r );
  409.         DrawGrowIcon( macWindow );
  410.     }
  411. }
  412.  
  413.  
  414. /*-----------------------------------***  CLICK  ***------------------------------------*/
  415. /*    
  416.  
  417. the user clicked in the content area of this window. By default this does nothing.
  418. ----------------------------------------------------------------------------------------*/
  419.  
  420. void    ZWindow::Click( const Point mouse, const short modifiers )
  421. {
  422. }
  423.  
  424.  
  425. /*-----------------------------***  CLICKINSAMEPLACE  ***-------------------------------*/
  426. /*    
  427.  
  428. should this click be considered a double-click? You can override this and return TRUE if
  429. the two points are to be considered in the same place for the purposes of determining
  430. a double-click. The default method always returns TRUE. The points passed are in the
  431. window's LOCAL coordinates.
  432.  
  433. ----------------------------------------------------------------------------------------*/
  434.  
  435. Boolean    ZWindow::ClickInSamePlace( const Point click1, const Point click2 )
  436. {
  437.     return TRUE;
  438. }
  439.  
  440.  
  441. /*-------------------------------***  SETSIZERECT  ***----------------------------------*/
  442. /*    
  443.  
  444. set minimum and maximum sizes for this window
  445. ----------------------------------------------------------------------------------------*/
  446.  
  447. void    ZWindow::SetSizeRect( const Rect& szRect )
  448. {
  449.     sizeRect = szRect;
  450.     
  451.     // make sure max is not less than min:
  452.     
  453.     sizeRect.right = MAX( sizeRect.right, sizeRect.left );
  454.     sizeRect.bottom = MAX( sizeRect.bottom, sizeRect.top );
  455.     
  456.     // if the window does not conform to the size constraints, change it's size so
  457.     // that it does.
  458.     
  459.     Rect        pr;
  460.     
  461.     pr = macWindow->portRect;
  462.     SetSize( pr.right - pr.left, pr.bottom - pr.top, FALSE );
  463. }
  464.  
  465.  
  466. /*-------------------------------***  GETSIZERECT  ***----------------------------------*/
  467. /*    
  468.  
  469. get minimum and maximum sizes for this window
  470. ----------------------------------------------------------------------------------------*/
  471.  
  472. void    ZWindow::GetSizeRect( Rect* szRect )
  473. {
  474.     *szRect = sizeRect;
  475. }
  476.  
  477.  
  478. /*----------------------------------***  CLOSE  ***-------------------------------------*/
  479. /*    
  480.  
  481. we want to close this window. If it needs to be saved, do that. The user may cancel this.
  482. ----------------------------------------------------------------------------------------*/
  483.  
  484. Boolean    ZWindow::Close( const short phase )
  485. {
  486.     // the user wants to close the window. This checks the dirty flag and if dirty, asks the
  487.     // user if they want to save changes, if so, this calls save.
  488.     
  489.     // first see if we have any subsidiary windows and ask them to close
  490.     
  491.     if (! CloseSubsidiaryWindows( phase ))
  492.         return FALSE;
  493.     
  494.     // they were all closed successfully, now check this one
  495.     
  496.     short check = kCloseNoSave;
  497.     
  498.     if ( dirty )
  499.     {
  500.         Str31    nameStr;
  501.         Str31    phaseStr;
  502.         
  503.         GetName( nameStr );
  504.         GetIndString( phaseStr, kMiscStrListID, ( phase == kRunning )? 1 : 2);
  505.         ParamText( nameStr, phaseStr, NULL, NULL );
  506.         
  507.         SetCursor( &qd.arrow );
  508.         check = Alert( kConfirmSaveAlertID, NULL );        // do you wish to save?
  509.         
  510.         if ( check == kConfirmSave )
  511.             if (! Save( FALSE ))                        // if so, save the file
  512.                 check = kCloseCancel;
  513.     }
  514.     
  515.     if ( check != kCloseCancel )
  516.     {
  517.         Hide();
  518.         
  519.         if ( gCurHandler == GetHandler())                // make the current handler this
  520.             gCurHandler = itsBoss;                        // one's boss- i.e. the application
  521.         
  522.         ForgetThis();
  523.         return TRUE;    // was closed
  524.     }
  525.     else
  526.         return FALSE;    // wasn't closed
  527. }
  528.  
  529.  
  530. /*---------------------------***  CLOSESUBSIDIARYWINDOWS  ***---------------------------*/
  531. /*    
  532. ask any windows supervised by this one to close
  533. ----------------------------------------------------------------------------------------*/
  534.  
  535. Boolean    ZWindow::CloseSubsidiaryWindows( const short phase )
  536. {
  537.     Boolean      allClosed = TRUE;
  538.     
  539.     if ( itsUnderlings )
  540.     {
  541.         // there are some commanders supervised by this object. If they are
  542.         // window objects, call their close method
  543.         
  544.         ZWindow*    w;
  545.         long        i = itsUnderlings->CountItems();
  546.         
  547.         while( i )
  548.         {
  549.             // use RTTI to make sure the object is some sort of window
  550.             
  551.             w = dynamic_cast<ZWindow*>(itsUnderlings->GetObject( i-- ));
  552.             
  553.             if (w)
  554.             {
  555.                 // yes it is, so ask it to close
  556.                 
  557.                 if (! w->Close( phase ))
  558.                 {
  559.                     // if it didn't close, then abandon the closure sequence
  560.                     
  561.                     allClosed = FALSE;
  562.                     break;
  563.                 }
  564.             }
  565.         }
  566.     }
  567.     
  568.     return allClosed;
  569. }
  570.  
  571.  
  572.  
  573. /*-----------------------------------***  HIDE  ***-------------------------------------*/
  574. /*    
  575.  
  576. make this window invisible
  577.  
  578. ----------------------------------------------------------------------------------------*/
  579.  
  580. void    ZWindow::Hide()
  581. {
  582.     gWindowManager->HideWindow( this );
  583. }
  584.  
  585.  
  586. /*-----------------------------------***  SHOW  ***-------------------------------------*/
  587. /*    
  588.  
  589. make this window visible
  590.  
  591. ----------------------------------------------------------------------------------------*/
  592.  
  593. void    ZWindow::Show()
  594. {
  595.     gWindowManager->ShowWindow( this );
  596. }
  597.  
  598.  
  599. /*---------------------------------***  SELECT  ***-------------------------------------*/
  600. /*    
  601.  
  602. make this window the active window
  603.  
  604. ----------------------------------------------------------------------------------------*/
  605.  
  606. void    ZWindow::Select()
  607. {
  608.     gWindowManager->SelectWindow( this );
  609. }
  610.  
  611.  
  612. /*---------------------------------***  PLACEAT  ***------------------------------------*/
  613. /*    
  614.  
  615. position the window on the screen at h, v.
  616.  
  617. ----------------------------------------------------------------------------------------*/
  618.  
  619. void    ZWindow::PlaceAt( const short hGlobal, const short vGlobal )
  620. {
  621.     MoveWindow( macWindow, hGlobal, vGlobal, FALSE );
  622. }
  623.  
  624.  
  625. /*------------------------------***  HANDLECOMMAND  ***---------------------------------*/
  626. /*    
  627.  
  628. handle commands for a window, like Save, Save As, Close, etc.
  629.  
  630. ----------------------------------------------------------------------------------------*/
  631.  
  632. void    ZWindow::HandleCommand( const long aCmd )
  633. {
  634.     EventRecord        ev;
  635.     
  636.     switch ( aCmd )
  637.     {
  638.         case kCmdClose:
  639.             gApplication->GetCurrentEvent( &ev );
  640.             
  641.             if ( ev.modifiers & optionKey )
  642.                 gApplication->CloseAll( Floats() );
  643.             else
  644.                 Close( kRunning );
  645.             break;
  646.         case kCmdSave:
  647.             Save( FALSE );
  648.             break;
  649.         case kCmdSaveAs:
  650.             Save( TRUE );
  651.             break;
  652.         case kCmdRevert:
  653.             Revert();
  654.             break;
  655.     }
  656.  
  657.     // pass other commands up to this object's boss (the app, in this case)
  658.     
  659.     inherited::HandleCommand( aCmd );
  660. }
  661.  
  662.  
  663. /*------------------------------***  HANDLECOMMAND  ***---------------------------------*/
  664.  
  665. void    ZWindow::HandleCommand( const short menuID, const short itemID )
  666. {
  667.     inherited::HandleCommand( menuID, itemID );
  668. }
  669.  
  670.  
  671. /*--------------------------------***  UPDATEMENUS  ***---------------------------------*/
  672. /*    
  673.  
  674. updet the menus for a window, like Save, Save As, Close, etc.
  675.  
  676. ----------------------------------------------------------------------------------------*/
  677.  
  678. void    ZWindow::UpdateMenus()
  679. {
  680.     // this enables the Close, Save and SaveAs commands.
  681.     
  682.     EventRecord        ev;
  683.     
  684.     gApplication->GetCurrentEvent( &ev );
  685.     
  686.     // show "Close All" if the option key is down, else "Close"
  687.     
  688.     if (ev.modifiers & optionKey )
  689.         gMenuBar->SetCommandText( kCmdClose, kMiscStrListID, 8 );
  690.     else
  691.         gMenuBar->SetCommandText( kCmdClose, kMiscStrListID, 9 );
  692.     
  693.     gMenuBar->EnableCommand( kCmdClose );
  694.     
  695.     if ( dirty )
  696.     {
  697.         gMenuBar->EnableCommand( kCmdSave );
  698.         
  699.         if ( isNamed )
  700.             gMenuBar->EnableCommand( kCmdRevert );
  701.     }
  702.     gMenuBar->EnableCommand( kCmdSaveAs );
  703.  
  704.     // call the boss to enable his menus
  705.     
  706.     inherited::UpdateMenus();
  707. }
  708.  
  709.  
  710. /*-----------------------------------***  SETTASK  ***----------------------------------*/
  711. /*    
  712. submit an undoable task for this window. This updates the global undo task and marks the
  713. document as dirty.
  714. ----------------------------------------------------------------------------------------*/
  715.  
  716. void        ZWindow::SetTask( ZUndoTask* aTask )
  717. {
  718.     // if were not dirty when the task arrives, then this must be the first task. Let it
  719.     // know so that if the task is undone, it can clear the dirty flag so that undoing the
  720.     // first task doesn't result in the "save changes?" alert.
  721.     
  722.     if ( ! dirty )
  723.         aTask->SetIsFirstTask();
  724.     
  725.     dirty = TRUE;    // document has been changed by the task
  726.     
  727.     gApplication->SetTask( aTask );    
  728. }
  729.  
  730.  
  731. /*---------------------------------***  SETSIZE  ***------------------------------------*/
  732. /*    
  733.  
  734. set this window to the width and height passed
  735. ----------------------------------------------------------------------------------------*/
  736.  
  737. void    ZWindow::SetSize( const short width, const short height, const Boolean reDraw )
  738. {
  739.     // sets the window's size to the width and height passed, constrained to sizeRect.
  740.     
  741.     short    w, h;
  742.     
  743.     w  = MIN( sizeRect.right,  MAX( width, sizeRect.left ));
  744.     h  = MIN( sizeRect.bottom, MAX( height, sizeRect.top ));
  745.  
  746.     if (( w != macWindow->portRect.right - macWindow->portRect.left ) ||
  747.         ( h != macWindow->portRect.bottom - macWindow->portRect.top ))
  748.     {
  749.         Focus();
  750.         if ( reDraw )
  751.             EraseRect( &macWindow->portRect );
  752.         
  753.         SizeWindow( macWindow, w, h, reDraw );
  754.         
  755.         if ( reDraw )
  756.             Draw();
  757.     }
  758. }
  759.  
  760.  
  761. /*-----------------------------------***  ZOOM  ***-------------------------------------*/
  762. /*    
  763.  
  764. Zoom this window between the standard and user states. This implements intelligent zoom-
  765. ing as recommended by the Apple HIG people. It may appear complex and indeed it probably
  766. is, however, the results are worth it since the zooming of windows almost always does
  767. exactly the most correct thing for your data- automatically! It also deals with any number
  768. of multiple monitors. You can always override this if you want something different.
  769. Based largely on code by Dean Yu, Apple Computer Inc.
  770. ----------------------------------------------------------------------------------------*/
  771.  
  772. #define        kNudgeSlop        2
  773. #define        kIconAllowance    64
  774.  
  775.  
  776. void    ZWindow::Zoom( const short partCode )
  777. {
  778.     RgnHandle    contRgn, strucRgn, scratchRgn;
  779.     Rect        portRect, crBBox, srBBox, zwBounds, wpOnScreen;
  780.     short        wfTop, wfLeft, wfBottom, wfRight;
  781.     long        largestArea = 0;
  782.     GDHandle    aScreen, targetMonitor;
  783.     
  784.     Focus();
  785.     EraseRect( &macWindow->portRect );
  786.     
  787.     // calculate the most intelligent zoom state for the window and set the
  788.     // standard state to it. The most intelligent state is on the monitor with
  789.     // the largest area of the window, and that involves the minimum amount of
  790.     // window movement.
  791.     
  792.     if ( partCode == inZoomOut )
  793.     {
  794.         GetWindowContentRgn( macWindow, contRgn = NewRgn());        // copland macro
  795.         GetWindowStructureRgn( macWindow, strucRgn = NewRgn());        // copland macro
  796.         portRect = macWindow->portRect;
  797.         crBBox = (*contRgn)->rgnBBox;
  798.         srBBox = (*strucRgn)->rgnBBox;
  799.         
  800.         // calculate the window frame size
  801.         
  802.         wfTop        = crBBox.top     - srBBox.top;
  803.         wfLeft        = crBBox.left     - srBBox.left;
  804.         wfBottom     = srBBox.bottom - crBBox.bottom;
  805.         wfRight     = srBBox.right     - crBBox.right;
  806.         
  807.         // the ideal size for this window is the max sizeRect. For scrollable windows,
  808.         // this is set according to the bounds, which will give us the expected results
  809.         // we now need to find the monitor that has the largest portion of the window
  810.         // intersecting it.
  811.         
  812.         scratchRgn = NewRgn();
  813.         SectRgn( GetGrayRgn(), contRgn, scratchRgn );
  814.         if (EmptyRgn( scratchRgn ))
  815.             zwBounds = srBBox;
  816.         else
  817.             zwBounds = crBBox;
  818.         DisposeRgn( scratchRgn );
  819.         
  820.         // re-use srBBox for the new standard state rect, initially set to the
  821.         // max sizeRect on the basis that this is the ideal window size if we had
  822.         // an infinitely large monitor.
  823.         
  824.         SetRect( &srBBox, 0, 0, sizeRect.right, sizeRect.bottom );
  825.         
  826.         // walk the device list to determine which monitor the window should be
  827.         // zoomed to:
  828.         
  829.         aScreen = GetDeviceList();
  830.         
  831.         while (aScreen)
  832.         {
  833.             long wpArea;
  834.             // find the intersection of the window and the screen
  835.             
  836.             SectRect( &zwBounds, &(*aScreen)->gdRect, &wpOnScreen );
  837.             
  838.             // find the area of this portion
  839.             
  840.             OffsetRect( &wpOnScreen, -wpOnScreen.left, -wpOnScreen.top );
  841.             wpArea = (long) wpOnScreen.right * (long) wpOnScreen.bottom;
  842.             
  843.             // if this is larger than the area found so far, keep track of
  844.             // the monitor that contains it
  845.             
  846.             if (wpArea > largestArea)
  847.             {
  848.                 largestArea = wpArea;
  849.                 targetMonitor = aScreen;
  850.             }
  851.             // look at the next monitor in the list
  852.             
  853.             aScreen = GetNextDevice( aScreen );
  854.         }
  855.         
  856.         // ok, we have found the monitor we wish to zoom to. Store the monitor's
  857.         // global rect in the wpOnScreen variable
  858.         
  859.         wpOnScreen = (*targetMonitor)->gdRect;
  860.         
  861.         // allow for the menubar and desktop icons if it's the main one
  862.         
  863.         if (targetMonitor == GetMainDevice())
  864.         {
  865.             wpOnScreen.top += GetMBarHeight();
  866.             wpOnScreen.right -= kIconAllowance;
  867.         }
  868.             
  869.         // OK, we can now calculate the standard rect we wish to zoom to (finally).
  870.         // We calculate this using srBBox, since that now holds the new std state
  871.         
  872.         OffsetRect( &srBBox, crBBox.left, crBBox.top );
  873.         srBBox.top       -= wfTop;
  874.         srBBox.left   -= wfLeft;
  875.         srBBox.right  += wfRight;
  876.         srBBox.bottom += wfBottom;
  877.         
  878.         // this is the ideal size for the window content. See if it needs nudging onto the
  879.         // monitor
  880.         
  881.         SectRect( &srBBox, &wpOnScreen, &zwBounds );
  882.         if (! EqualRect( &srBBox, &zwBounds ))
  883.         {
  884.             // needs to be nudged onto the monitor.
  885.             
  886.             short    oH, oV;
  887.             
  888.             oH = CalculateOffsetAmount( srBBox.left, srBBox.right,
  889.                                         zwBounds.left, zwBounds.right,
  890.                                         wpOnScreen.left, wpOnScreen.right );
  891.             oV = CalculateOffsetAmount( srBBox.top, srBBox.bottom,
  892.                                         zwBounds.top, zwBounds.bottom,
  893.                                         wpOnScreen.top, wpOnScreen.bottom );
  894.             OffsetRect( &srBBox, oH, oV );
  895.         }
  896.         
  897.         // If this still falls off the screen in any direction, it means that it is too large
  898.         // for the montior, so it will need to be shrunk down to fit.
  899.         
  900.         SectRect( &srBBox, &wpOnScreen, &zwBounds);
  901.         if (! EqualRect( &srBBox, &zwBounds ))
  902.         {
  903.             // nope- still doesn't fit. So shrink it down.
  904.             
  905.             if ((srBBox.right - srBBox.left) > (wpOnScreen.right - wpOnScreen.left))
  906.             {
  907.                 srBBox.left = wpOnScreen.left + kNudgeSlop;
  908.                 srBBox.right = wpOnScreen.right - kNudgeSlop;
  909.             }
  910.             
  911.             if ((srBBox.bottom - srBBox.top) > (wpOnScreen.bottom - wpOnScreen.top))
  912.             {
  913.                 srBBox.top = wpOnScreen.top + kNudgeSlop;
  914.                 srBBox.bottom = wpOnScreen.bottom - kNudgeSlop;
  915.             }
  916.         }
  917.         
  918.         // adjust for the thickness of the frame and set the standard rect
  919.         
  920.         srBBox.top       += wfTop;
  921.         srBBox.left   += wfLeft;
  922.         srBBox.right  -= wfRight;
  923.         srBBox.bottom -= wfBottom;
  924.         
  925.         SetStdZoomRect( srBBox );
  926.         
  927.         DisposeRgn( contRgn );
  928.         DisposeRgn( strucRgn );
  929.     }
  930.     
  931.     // and.... Zoom!
  932.     
  933.     ZoomWindow( macWindow, partCode, FALSE );
  934. }
  935.  
  936.  
  937. /*------------------------------***  SETSTDZOOMRECT  ***--------------------------------*/
  938. /*    
  939. set the std rect for zoomable windows. The window zooms to this rect when the zoom box
  940. is clicked. If the window is not zoomable, this does nothing. The rect is in global coords.
  941. ----------------------------------------------------------------------------------------*/
  942.  
  943. void    ZWindow::SetStdZoomRect( const Rect& aRect )
  944. {
  945.     short    v = GetWVariant(macWindow);
  946.  
  947.     if (v == zoomDocProc ||
  948.         v == zoomNoGrow)
  949.         SetWindowStandardState( macWindow, &aRect );    // using copland macro
  950. }
  951.  
  952.  
  953. /*-----------------------------------***  SAVE  ***-------------------------------------*/
  954. /*    
  955.  
  956. save the contents of the window to a file. This may display the standard file dialog.
  957. ----------------------------------------------------------------------------------------*/
  958.  
  959.  
  960. Boolean    ZWindow::Save( const Boolean forceSaveAs )
  961. {
  962.     // handles the save and save as commands.
  963.     
  964.     if (! isNamed || forceSaveAs)
  965.     {
  966.         // do Save As
  967.         
  968.         StandardFileReply    macReply;
  969.         
  970.         PickFile( &macReply );
  971.         
  972.         if (macReply.sfGood)
  973.             macFile = macReply.sfFile;
  974.         else
  975.             return FALSE;        // user cancelled the save
  976.     }
  977.     
  978.     // now do a save with the info.
  979.     
  980.     SetWatchCursor();
  981.     SaveFile();
  982.     
  983.     return TRUE;
  984. }
  985.  
  986.  
  987. /*---------------------------------***  PICKFILE  ***-----------------------------------*/
  988. /*    
  989.  
  990. display standard file dialog for picking a file for saving. Override if you want custom
  991. dialog, etc.
  992.  
  993. ----------------------------------------------------------------------------------------*/
  994.  
  995. void    ZWindow::PickFile( StandardFileReply* macReply )
  996. {
  997.     Str31    prompt;
  998.     Str255     name;
  999.     
  1000.     GetIndString( prompt, kMiscStrListID, 3 );
  1001.     GetName( name );
  1002.     
  1003.     // make sure that filename is no longer than 31 chars
  1004.     
  1005.     name[0] = MIN( name[0], 31 );
  1006.     
  1007.     gWindowManager->Deactivate();
  1008.     StandardPutFile( prompt, name, macReply );
  1009.     gWindowManager->Activate();
  1010. }
  1011.  
  1012.  
  1013. /*---------------------------------***  SAVEFILE  ***-----------------------------------*/
  1014. /*    
  1015.  
  1016. write out the contents of the window to a file. This may rename the window. Note that you
  1017. need to override this to actually write to a file (using a ZFile, perhaps), then call the
  1018. inherited method to set the name and the state flags.
  1019.  
  1020. ----------------------------------------------------------------------------------------*/
  1021.  
  1022.  
  1023. void    ZWindow::SaveFile()
  1024. {
  1025.     // actually save the window's contents to the file.
  1026.     
  1027.     if (macFile.vRefNum != kNoFile)
  1028.     {
  1029.         SetTitle( macFile.name );
  1030.         
  1031.         // no longer dirty
  1032.         
  1033.         isNamed = TRUE;
  1034.         dirty = FALSE;
  1035.     }
  1036. }
  1037.  
  1038.  
  1039. /*---------------------------------***  GETNAME  ***------------------------------------*/
  1040. /*    
  1041.  
  1042. return the name of the window
  1043.  
  1044. ----------------------------------------------------------------------------------------*/
  1045.  
  1046. void    ZWindow::GetName( Str255 name )
  1047. {
  1048.     GetWTitle( macWindow, name );
  1049. }
  1050.  
  1051.  
  1052.  
  1053. /*----------------------------------***  REVERT  ***------------------------------------*/
  1054. /*    
  1055.  
  1056. revert the contents of the window to the original file
  1057.  
  1058. ----------------------------------------------------------------------------------------*/
  1059.  
  1060. void    ZWindow::Revert()
  1061. {
  1062.     // revert the contents. By default, this just calls open.
  1063.     
  1064.     Str31    title;
  1065.     
  1066.     GetName( title );
  1067.     ParamText( title, NULL, NULL, NULL );
  1068.     
  1069.     if ( Alert( kRevertConfirmAlertID, NULL ) == ok )
  1070.     {
  1071.         SetWatchCursor();
  1072.         OpenFile( macFType );
  1073.     }
  1074. }
  1075.  
  1076.  
  1077. /*---------------------------------***  SETFILE  ***------------------------------------*/
  1078. /*    
  1079.  
  1080. set the filespec for this window to the file passed.
  1081.  
  1082. ----------------------------------------------------------------------------------------*/
  1083.  
  1084. void    ZWindow::SetFile( const FSSpec& aFile )
  1085. {
  1086.     macFile = aFile;
  1087. }
  1088.  
  1089.  
  1090. /*---------------------------------***  OPENFILE  ***-----------------------------------*/
  1091. /*    
  1092.  
  1093. open the file into the window's contents. This will set the name of the window to equal
  1094. the filename
  1095.  
  1096. ----------------------------------------------------------------------------------------*/
  1097.  
  1098. void    ZWindow::OpenFile( const OSType aFileType )
  1099. {
  1100.     // this opens the current file into this window. This function should read the
  1101.     // contents of the file, replacing the current contents. The default method
  1102.     // does nothing. You should check that the vRefNum of the file spec is no kNoFile.
  1103.     
  1104.     if (macFile.vRefNum != kNoFile)
  1105.     {
  1106.         macFType = aFileType;
  1107.         
  1108.         SetTitle(macFile.name);
  1109.         isNamed = TRUE;
  1110.         
  1111.         if (IsVisible())
  1112.             PostRefresh();
  1113.             
  1114.         // delete any existing undo task for this window after opening a file,
  1115.         // since it probably contains stale data.
  1116.         
  1117.         ZUndoTask*    task = gApplication->GetUndoTask();
  1118.         
  1119.         if (task && (task->GetUndoTarget() == this))
  1120.             gApplication->SetTask( NULL );
  1121.         
  1122.         dirty = FALSE;
  1123.     }
  1124. }
  1125.  
  1126.  
  1127. /*---------------------------------***  SETTITLE  ***-----------------------------------*/
  1128. /*    
  1129.  
  1130. set the title of the window
  1131. ----------------------------------------------------------------------------------------*/
  1132.  
  1133. void    ZWindow::SetTitle( Str255 aTitle )
  1134. {
  1135.     SetWTitle( macWindow, aTitle );
  1136. }
  1137.  
  1138.  
  1139.  
  1140. /*--------------------------------***  GETHANDLER  ***----------------------------------*/
  1141. /*    
  1142.  
  1143. return the object that begins the chain of command for this window. By default, it is the
  1144. window itself.
  1145.  
  1146. ----------------------------------------------------------------------------------------*/
  1147.  
  1148. ZCommander*    ZWindow::GetHandler()
  1149. {
  1150.     return this;
  1151. }
  1152.  
  1153.  
  1154. /*-------------------------------***  ADJUSTCURSOR  ***---------------------------------*/
  1155. /*    
  1156.  The cursor is over this window. Set its shape according to where it is and what modifiers
  1157.  are down. By default this just sets the cursor to an arrow. <mouse> is in local coords.
  1158.  
  1159. ----------------------------------------------------------------------------------------*/
  1160.  
  1161. void    ZWindow::AdjustCursor( const Point mouse, const short modifiers )
  1162. {
  1163.     SetCursor( &qd.arrow );
  1164. }
  1165.  
  1166.  
  1167. /*---------------------------------***  ISVISIBLE  ***----------------------------------*/
  1168. /*    
  1169.  Is the window visible on screen?
  1170. ----------------------------------------------------------------------------------------*/
  1171.  
  1172. Boolean    ZWindow::IsVisible()
  1173. {
  1174.     return ((WindowPeek) macWindow)->visible;
  1175. }
  1176.  
  1177.  
  1178. /*-----------------------------***  GETTITLEBARHEIGHT  ***------------------------------*/
  1179. /*    
  1180.  return the actual height of the window's title bar. This measures it from the regions
  1181.  and is thus totally WDEF safe.
  1182. ----------------------------------------------------------------------------------------*/
  1183.  
  1184. short    ZWindow::GetTitleBarHeight()
  1185. {
  1186.     RgnHandle    sRgn, cRgn;
  1187.     short        tHeight;
  1188.     
  1189.     FailNIL( sRgn = NewRgn());
  1190.     FailNIL( cRgn = NewRgn());
  1191.     
  1192.     GetStructureRegion( sRgn );
  1193.     GetContentRegion( cRgn );
  1194.     
  1195.     tHeight =  (*cRgn)->rgnBBox.top - (*sRgn)->rgnBBox.top;
  1196.     
  1197.     DisposeRgn( sRgn );
  1198.     DisposeRgn( cRgn );
  1199.     
  1200.     return tHeight;
  1201. }
  1202.  
  1203.  
  1204. /*----------------------------***  GETSTRUCTUREREGION  ***------------------------------*/
  1205. /*    
  1206.  copies the window's structure region into the passed region
  1207. ----------------------------------------------------------------------------------------*/
  1208.  
  1209. void    ZWindow::GetStructureRegion( RgnHandle aRgn )
  1210. {
  1211.     FailNILParam( aRgn );
  1212.     
  1213.     WindowPeek    w = ( WindowPeek ) macWindow;
  1214.     
  1215.     Boolean wasFudged = FALSE;
  1216.     short    h, v;
  1217.     
  1218.     // if the window isn't visible, the structure region isn't valid, so we have to
  1219.     // make it visible offscreen in order to get the region
  1220.     
  1221.     if ( ! w->visible )
  1222.     {
  1223.         
  1224.         GetGlobalPosition( &h, &v ); 
  1225.         
  1226.         MoveWindow( macWindow, h + 10000, v + 100, FALSE );
  1227.         ShowWindow( macWindow );
  1228.         
  1229.         wasFudged = TRUE;
  1230.     }
  1231.     
  1232.     CopyRgn( w->strucRgn, aRgn );
  1233.     
  1234.     if ( wasFudged )
  1235.     {
  1236.         HideWindow( macWindow );    
  1237.         MoveWindow( macWindow, h, v, FALSE );
  1238.     }
  1239. }
  1240.  
  1241.  
  1242. /*-----------------------------***  GETCONTENTREGION  ***-------------------------------*/
  1243. /*    
  1244.  copies the window's content region into the passed region
  1245. ----------------------------------------------------------------------------------------*/
  1246.  
  1247. void    ZWindow::GetContentRegion( RgnHandle aRgn )
  1248. {
  1249.     FailNILParam( aRgn );
  1250.     
  1251.     WindowPeek    w = ( WindowPeek ) macWindow;
  1252.     
  1253.     Boolean wasFudged = FALSE;
  1254.     short    h, v;
  1255.     
  1256.     // if the window isn't visible, the content region isn't valid, so we have to
  1257.     // make it visible offscreen in order to get the region
  1258.     
  1259.     if ( ! w->visible )
  1260.     {
  1261.         
  1262.         GetGlobalPosition( &h, &v ); 
  1263.         
  1264.         MoveWindow( macWindow, h + 10000, v + 100, FALSE );
  1265.         ShowWindow( macWindow );
  1266.         
  1267.         wasFudged = TRUE;
  1268.     }
  1269.     
  1270.     CopyRgn( w->contRgn, aRgn );
  1271.     
  1272.     if ( wasFudged )
  1273.     {
  1274.         HideWindow( macWindow );    
  1275.         MoveWindow( macWindow, h, v, FALSE );
  1276.     }
  1277. }
  1278.  
  1279.  
  1280. /*-------------------------***  GETSTRUCTUREFRAMEBORDER  ***----------------------------*/
  1281. /*    
  1282.  returns in <aRect> the thicknesses of the window borders. <top> is the title bar height,
  1283.  <left> and <right> are the thicknesses of the edges, and <bottom> is the thickness of the
  1284.  bottom.
  1285. ----------------------------------------------------------------------------------------*/
  1286.  
  1287. void    ZWindow::GetStructureFrameBorder( Rect* aRect )
  1288. {
  1289.     RgnHandle    sRgn, cRgn;
  1290.     Rect        s, c;
  1291.     
  1292.     FailNILParam( aRect );
  1293.     
  1294.     FailNIL( sRgn = NewRgn());
  1295.     FailNIL( cRgn = NewRgn());
  1296.     
  1297.     GetStructureRegion( sRgn );
  1298.     GetContentRegion( cRgn );
  1299.     
  1300.     s = (*sRgn)->rgnBBox;
  1301.     c = (*cRgn)->rgnBBox;
  1302.     
  1303.     aRect->top         = c.top    - s.top;
  1304.     aRect->left     = c.left   - s.left;
  1305.     aRect->right     = s.right  - c.right;
  1306.     aRect->bottom     = s.bottom - c.bottom;
  1307.     
  1308.     DisposeRgn( sRgn );
  1309.     DisposeRgn( cRgn );
  1310. }
  1311.  
  1312.  
  1313. /*-----------------------------***  GETGLOBALPOSITION  ***------------------------------*/
  1314. /*    
  1315.  returns the global position of the window on screen
  1316. ----------------------------------------------------------------------------------------*/
  1317.  
  1318. void    ZWindow::GetGlobalPosition( short* hGlobal, short* vGlobal )
  1319. {
  1320.     GrafPtr        savePort;
  1321.     Point        gloc;
  1322.     
  1323.     GetPort( &savePort );
  1324.     SetPort( macWindow );
  1325.     
  1326.     gloc = topLeft( macWindow->portRect );
  1327.     LocalToGlobal( &gloc );
  1328.     
  1329.     SetPort( savePort );
  1330.     
  1331.     *hGlobal = gloc.h;
  1332.     *vGlobal = gloc.v;
  1333. }
  1334.  
  1335.  
  1336. #pragma mark -
  1337. /*---------------------------------******************----------------------------------*/
  1338.  
  1339. static short CalculateOffsetAmount(short idealStartPoint, short idealEndPoint, short idealOnScreenStartPoint,
  1340.                             short idealOnScreenEndPoint, short screenEdge1, short screenEdge2)
  1341. {
  1342.     short    offsetAmount;
  1343.  
  1344.     // First check to see if the window fits on the screen in this dimension.
  1345.     if ((idealStartPoint < screenEdge1) && (idealEndPoint > screenEdge2))
  1346.         offsetAmount = 0;
  1347.     else
  1348.     {
  1349.     
  1350.         // Find out how much of the window lies off this screen by subtracting the amount of the window
  1351.         // that is on the screen from the size of the entire window in this dimension. If the window
  1352.         // is completely offscreen, the offset amount is going to be the distance from the ideal
  1353.         // starting point to the first edge of the screen.
  1354.         if ((idealOnScreenStartPoint - idealOnScreenEndPoint) == 0)
  1355.         {
  1356.             // See if the window is lying to the left or above the screen
  1357.             if (idealEndPoint < screenEdge1)
  1358.                 offsetAmount = screenEdge1 - idealStartPoint + kNudgeSlop;
  1359.             else
  1360.             // Otherwise, it’s below or to the right of the screen
  1361.                 offsetAmount = screenEdge2 - idealEndPoint - kNudgeSlop;
  1362.         }
  1363.         else
  1364.         {
  1365.             // Window is already partially or completely on the screen
  1366.             offsetAmount = (idealEndPoint - idealStartPoint) -
  1367.                             (idealOnScreenEndPoint - idealOnScreenStartPoint);
  1368.     
  1369.             // If we are offscreen a little, move the window in a few more pixels from the edge of the screen.
  1370.             if (offsetAmount != 0)
  1371.                 offsetAmount += kNudgeSlop;
  1372.             
  1373.             // Check to see which side of the screen the window was falling off of, so that it can be
  1374.             // nudged in the opposite direction.
  1375.             if (idealEndPoint > screenEdge2)
  1376.                 offsetAmount = -offsetAmount;
  1377.         }
  1378.     }
  1379.     
  1380.     return offsetAmount;
  1381. }
  1382.  
  1383.